<?php

require_once 'Pipes/FileSystem/ModelList/Finder.php';
require_once 'Pipes/FileSystem/ModelList/Loader.php';
require_once 'Pipes/FileSystem/ModelMeta/Finder.php';
require_once 'Pipes/FileSystem/ModelMeta/Loader.php';
require_once 'PipesImpl/Config.php';
require_once 'PipesImpl/Model/Relationship/Mapper.php';
require_once 'Pipes/Namespace/Parser.php';
require_once 'Pipes/Model/Mapper/Factory.php';

class Pipes_Model_Relationship_Mapper implements PipesImpl_Model_Relationship_Mapper
{
	private $_pdo = null;
	private $_config = null;
	private $_model = null;
	private $_listLoader = null;
	private $_metaLoader = null;
	
	public function __construct(PipesImpl_Config $config, PipesImpl_Model $model) {
		$this->_pdo = $config->pdo;
		$this->_config = $config;
		$this->_model = $model;

		$this->_listLoader = new Pipes_FileSystem_ModelList_Loader(
			new Pipes_FileSystem_ModelList_Finder($config)
		);

		$this->_metaLoader = new Pipes_FileSystem_ModelMeta_Loader(
			new Pipes_FileSystem_ModelMeta_Finder($config)
		);
	}
	
	public function getList($relationship) {
		// load Mapper - makes sure this really exists and also allows the 
		// mapper to do any initialization that is required
		$factory = new Pipes_Model_Mapper_Factory($this->_config);
		$mapper = $factory->factory($relationship);
		
		$modelName = $this->_model->getName() . 's';
		$modelId = $this->_model->idColumn()->name;
		$relationshipName = $relationship . 's';
		$relationshipId = $relationship . '_id';
		$sql = "
			SELECT 
				{$relationshipName}.*
			FROM 
				{$modelName}
				INNER JOIN {$modelName}_to_{$relationshipName} USING ({$modelId})
				INNER JOIN {$relationshipName} USING ({$relationshipId})
			WHERE
				{$modelName}.{$modelId} = ?";
		$statement = $this->_pdo->prepare($sql);
		$statement->execute(array($this->_model->$modelId));
		
		$recordSet = $statement->fetchAll(PDO::FETCH_ASSOC);
		$statement->closeCursor();
		
		$namespace = $this->_config->namespace;
		$name = ucfirst($relationship);
		
		$this->_listLoader->load($name);
		$modelListName = $this->_listLoader->lastLoaded;

		$this->_metaLoader->load($name);
		$metaName = $this->_metaLoader->lastLoaded;
		$meta = new $metaName($this->_config);
		
		$modelList = new $modelListName($this->_config, $meta, $recordSet);
		$modelList->attachSave(array($this, 'save'));
		$modelList->attachRemove(array($this, 'remove'));
		return  $modelList;
	}
	
	public function save(PipesImpl_Model $model) {
		$isNew = $model->isNew();
		$factory = new Pipes_Model_Mapper_Factory($this->_config);
		$mapper = $factory->factory($model->getName());
		
		$mapper->save($model);
		
		$modelName = $this->_model->getName() . 's';
		$modelId = $this->_model->idColumn()->name;
		$relationshipName = $model->getName() . 's';
		$relationshipId = $model->idColumn()->name;

		if ($isNew) {
			$sql = "
				INSERT INTO 
					{$modelName}_to_{$relationshipName}
				VALUES
					(:{$modelId}, :{$relationshipId})";
			$statement = $this->_pdo->prepare($sql);
			
			$params = array(
				":{$modelId}" => $this->_model->$modelId,
				":{$relationshipId}" => $model->$relationshipId
			);
			$statement->execute($params);
		} else {
			$sql = "REPLACE INTO
						{$modelName}_to_{$relationshipName}
					VALUES
						(:{$modelId}, :{$relationshipId})";
			$statement = $this->_pdo->prepare($sql);
			$params = array(
				":{$modelId}" => $this->_model->$modelId,
				":{$relationshipId}" => $model->$relationshipId
			);
			
			$statement->execute($params);
		}
	}

	public function remove(PipesImpl_Model $model) {
		$modelId = $this->_model->idColumn()->name;
		$relationshipId = $model->idColumn()->name;
		$sql = "
			DELETE FROM 
				{$this->_model->getName()}s_to_{$model->getName()}s
			WHERE
				{$modelId} = ?
				AND {$relationshipId} = ?
			LIMIT 1";

		$statement = $this->_pdo->prepare($sql);
		$statement->execute(
			array(
				$this->_model->$modelId,
				$model->$relationshipId
			)
		);
	}
}
